package com.specter.serv.controller;

import static com.specter.sure.core.AuthConsts.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.specter.mvc.model.Response;
import com.specter.serv.service.UserDetailService;
import com.specter.sure.core.AuthConfig;
import com.specter.sure.core.AuthContext;
import com.specter.sure.core.Authorized;
import com.specter.sure.core.AuthorizedProvider;
import com.specter.utils.CookieUtils;
import com.specter.utils.JSONUtils;
import com.specter.utils.StringUtils;
import com.specter.utils.URLUtils;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

/**
 * 登录认证服务(Client)
 * 
 * @author Liang.Wang
 * @since 2025-04-02 12:12:12
 */
@Slf4j
@RestController
@RequestMapping("/sure/nauth")
public class AuthNativeController {

	private @Autowired AuthConfig PROP;
	private @Autowired AuthorizedProvider authentication;
	private @Autowired UserDetailService userDetailService;

	/**
	 * Filter中 认证/授权 错误后处理输出
	 */
	@RequestMapping("/failure")
	public ResponseEntity<?> failure(HttpServletRequest request, HttpServletResponse response) {
		Boolean isAuthorize = (Boolean) request.getAttribute("isAuthorize");

		ResponseEntity<?> res = null;
		if (Boolean.FALSE.equals(isAuthorize)) {
			if (PROP.AUTHORIZE_URL_REMEMBER) {
				request.getSession().setAttribute(KEY_SESSION_FROM, request.getRequestURL());
			}
			// 5、去中心认证服务器去检查登录状态
			if (PROP.SSO_ENABLE) {// 服务校验请求
				AuthContext.getSession().setAttribute(KEY_SESSION_FROM, request.getRequestURL());
				String url = PROP.SSO_SERVER + URL_SAUTH_AUTHORIZE; // 发出客户端重定向检查地址指令
				url += "?response_type=code&redirect_uri=";
				url += PROP.SSO_CALLBACK.startsWith("http") ? "" : URLUtils.getRequestCTX(request) + PROP.SSO_CALLBACK;

				// url += "&access_token=access_token_string";
				System.out.println("1/redirect to sso:" + url);
				// 重定向到服务器去校验服务器是否登录
				return ResponseEntity.status(HttpStatus.FOUND).header(HttpHeaders.LOCATION, url).build();
			}
			
			log.debug("$$$ Authorize failed, please login!");
			res = ResponseEntity.ok().body(Response.failure(ERROR_AUTHORIZE_EXCEPTION).data("target", PROP.AUTHORIZE_URL_FAILURE));
		} else {// 此时一定是 isPrivilege = false;
			log.debug("$$$ Privilege failed, please check!");
			res = ResponseEntity.ok().body(Response.failure(ERROR_PRIVILEGE_EXCEPTION).data("target", PROP.PRIVILEGE_URL_FAILURE));
		}

		return res;
	}

	/**
	 * 登录提交方法
	 */
	@PostMapping("/authorize")
	public ResponseEntity<?> authorize(HttpServletRequest request, HttpServletResponse response) {
		if (PROP.AUTHORIZE_CAPTCHA_VALIDATE && userDetailService.validate(request.getParameter("userinfo"))) {// 验证码错误
			return ResponseEntity.ok().body(Response.failure(ERROR_CAPTCHA_ERROR).data("target", PROP.AUTHORIZE_URL_FAILURE));
		}

		String accounts = request.getParameter(PROP.AUTHORIZE_USERNAME_KEY);
		String password = request.getParameter(PROP.AUTHORIZE_PASSWORD_KEY);
		Authorized detail = userDetailService.userinfo(accounts);

		if (detail == null) {// 用户找不到
			return ResponseEntity.ok().body(Response.failure(ERROR_NOUSER_ERROR).data("target", PROP.AUTHORIZE_URL_FAILURE));
		}

		if (!StringUtils.equals(authentication.encode(accounts, password), detail.getPassword())) {// 密码错误
			return ResponseEntity.ok().body(Response.failure(ERROR_PASSWORD_ERROR).data("target", PROP.AUTHORIZE_URL_FAILURE));
		}

		String jwt = authentication.login(detail);// ------ 内部预设置登录 ------

		// 1、设置登录session信息
		request.getSession().setAttribute(TOKEN_FROM_SESSION, jwt);
		// 2、设置登录cookies信息
		CookieUtils.addAESCookie(response, TOKEN_FROM_COOKIE, jwt);

		String target = (String) request.getSession().getAttribute(KEY_SESSION_FROM);
		target = StringUtils.isBlank(target) ? PROP.AUTHORIZE_URL_SUCCESS : target;
		return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(Response.success().data("target", target));
	}

	/**
	 * 退出提交方法
	 */
	@RequestMapping("/invalidate")
	public ResponseEntity<?> invalidate(HttpServletRequest request, HttpServletResponse response) {
		Authorized subject = AuthContext.getUserDetail();

		authentication.logix(subject);// ------ 内部预设置登出 ------

		// 1、设置登录session信息
		request.getSession().removeAttribute(TOKEN_FROM_SESSION);
		// 2、设置登录cookies信息
		CookieUtils.removeCookie(request, response, TOKEN_FROM_COOKIE);

		return ResponseEntity.ok().body(Response.success().data("target", PROP.AUTHORIZE_URL_LOGOUT));
	}

	/**
	 * 
	 * 接收服务端响应，获得中央服务器的用户信息并登录本地
	 * 
	 * @param request 包括登录code
	 * @return 登录成功跳转地址
	 */
	@RequestMapping("/callback")
	public String callback(HttpServletRequest request) {
		String authorizationCode = request.getParameter("code");

		String url = PROP.SSO_SERVER + URL_SAUTH_GIVE2ME + "?code=" + authorizationCode;
		ResponseEntity<String> res = (new RestTemplate()).getForEntity(url, String.class);
		String loginId = (String) JSONUtils.json2bean(res.getBody()).get("username");

		Authorized subject = userDetailService.userinfo(loginId);
		// ------ 内部预设置登录 ------//
		String jwt = authentication.login(subject);// 更新一下
		// 1、设置登录session信息
		request.getSession().setAttribute(TOKEN_FROM_SESSION, jwt);
		// 2、设置登录cookies信息
		CookieUtils.addAESCookie(AuthContext.getResponse(), TOKEN_FROM_COOKIE, jwt);
		// 3、设置登录headers信息
		AuthContext.getResponse().addHeader("refresh_token", jwt);// 方便存在localstorage

		// userAuthorizeService.login(request, AuthContext.getResponse());
		// ------ 用户自定义登录 ------ //

		Object redirect_uri = request.getSession().getAttribute(KEY_SESSION_FROM);// 来自filter的设置
		request.getSession().removeAttribute(KEY_SESSION_FROM);

		System.out.println("3/client success then orign request url:" + redirect_uri);
		if (redirect_uri != null) {
			return "redirect:" + redirect_uri.toString();
		} else {
			log.debug("callback error!");
			return "callback error!";// 返回空值
		}
	}

}
